import React, { useState, useEffect, useRef } from 'react';
import { Graph, Cell, Node, Edge } from '@antv/x6';
import Lane from './components/Lane';
import List from './components/List';
import CreateNode from './components/CreateNode';
import ActionButtons from './components/ActionButtons';
import { Spin } from 'antd';
import { usePersistFn, useInterval, useDebounceEffect } from 'ahooks';
import useHooks from './useHooks';
import {
  getGraphData,
  nextTick,
  createGraphNodeData,
  getLabelText,
  dbHelper,
  autoSaveJson,
} from './tools';
import defaultData from './defaultData';
import './components/assets/font/iconfont';
import 'antd/dist/antd.css';
import defaultAssets from './components/assets';
import './style/index';

(window as any)._globalAssets = defaultAssets;

export interface ModuleItem {
  label: string | React.ReactNode;
  value: string | number;
  children: SelectOption[];
  [key: string]: any;
}

export interface ModuleConfig {
  title: string;
  search?: {
    placeholder?: string;
  };
  options: ModuleItem[];
}

interface ArchDesignProps {
  assets?: { [key: string]: string };
  data: any;
  moduleConfig: ModuleConfig;
  saveInterval?: number; // 数据自动保存的间隔时间 默认为5s
  onAddLink?: (link: Edge) => Promise<boolean>;
  onRemoveLink?: (links: Edge[]) => Promise<boolean>;
  onRemoveNode?: (nodes: Node[]) => Promise<boolean>;
  onCreateNode?: (nodeData: any) => Promise<any>;
  onUpdateNode?: (nodeData: any) => Promise<any>;
  onUndoOrRedo?: (
    type: 'undo' | 'redo',
    graph: Graph,
    args: { cmds: any[]; options: any },
  ) => void;
  onSave?: (data: any) => Promise<boolean>;
}
const ArchDesign: React.FC<ArchDesignProps> = function ({
  assets,
  moduleConfig,
  data,
  onAddLink,
  onRemoveLink,
  onRemoveNode,
  onCreateNode,
  onUpdateNode,
  onUndoOrRedo,
  onSave,
  saveInterval = 10000,
}) {
  (window as any)._saveInterval = saveInterval;
  const archWrapper = useRef(null);
  const [graph, setGraph] = useState<Graph>();
  const [visible, setVisible] = useState<boolean>(false);
  const [initLoading, setInitLoading] = useState<boolean>(true);
  const [canRedo, setCanRedo] = useState<boolean>(false);
  const [canUndo, setCanUndo] = useState<boolean>(false);
  const [currentCell, setCurrentCell] = useState<Cell>();
  const [laneOptions, setLaneOptions] = useState<SelectOption[]>([]);
  const [graphData, setGraphData] = useState(defaultData);
  const [assetsData, setAssetsData] = useState((window as any)._globalAssets);
  const [zoom, setZoom] = useState<number>(1);
  // 全屏显示
  const [isFullScreen, setIsFullScreen] = useState<boolean>(false);
  // 初始化数据
  // 从 indexdb 中恢复数据
  const restoreData = usePersistFn(async () => {
    setInitLoading(true);
    await dbHelper.ready();
    const store: any = await dbHelper.findByPk('graphDatas', '1');
    const { id: storeId, updateTime, expired, data: storeData } = store || {};
    let nodeDatas: any = data;
    if (storeId && updateTime + expired > Date.now()) {
      if (storeData) nodeDatas = storeData;
    }
    setLaneOptions(
      nodeDatas.lanes.map(({ id, name }: any) => ({ label: name, value: id })),
    );
    setGraphData(getGraphData(nodeDatas));
    setInitLoading(false);
    await autoSaveJson(null, graph);
  });
  // 自动保存
  useInterval(async () => {
    await autoSaveJson(null, graph);
  }, saveInterval);
  // 合并资源
  useEffect(() => {
    const globalAssets = { ...assetsData, ...(assets || {}) };
    (window as any)._globalAssets = globalAssets;
    setAssetsData(globalAssets);
  }, [assets]);

  useDebounceEffect(() => {
    restoreData();
  }, [data]);

  // 生成事件
  const { actionFunMap } = useHooks({
    onRemoveLink,
    onRemoveNode,
    onAddLink,
    onSave,
  });

  // 画布事件响应
  const handlerActions = usePersistFn((action: string) => {
    actionFunMap[action] &&
      actionFunMap[action](currentCell, graph, {
        setVisible,
        setCurrentCell,
        setZoom,
        zoom,
        fullContainer: archWrapper.current,
        setIsFullScreen,
      });
  });

  // 拖拽进入创建环节
  const dragToCreateNode = (node: Node) => {
    setCurrentCell(node);
    nextTick(() => setVisible(true));
  };

  // 创建新节点
  const addNewNode = usePersistFn((nodeData: any) => {
    const lane = graph?.getCellById(nodeData.preId);
    const node = graph?.createNode(
      createGraphNodeData(nodeData, { graph, assets: assetsData }),
    );
    if (node && lane) {
      lane.addChild(node);
    }
    if (currentCell) {
      graph?.removeCell(currentCell);
      setCurrentCell(undefined);
    }
  });
  // 修改节点信息
  const updateNode = usePersistFn((node: Node) => {
    const nodeData: any = node.data || {};
    const { moduleType, name, systemType } = nodeData;
    const data = {
      image: `${(moduleType || '').toLowerCase()}Module`,
      bgImage: `${(systemType || '').toLowerCase()}System`,
    };
    const grahpNode = graph?.getCellById(nodeData.id);
    grahpNode?.setData({ ...nodeData, ...data }, { silent: true });
    grahpNode?.attr({
      text: {
        text: getLabelText({
          label: name,
          maxTextLen: 20,
          maxLine: 2,
          placehoder: '...',
        }),
      },
      itemTag: { xlinkHref: assetsData[data.image] },
      backgorund: { xlinkHref: assetsData[data.bgImage] },
    });
  });

  // 创建或修改节点信息
  const submitNode = usePersistFn(async (node: Node) => {
    let flag: boolean = false;
    let nodeData: any = node.data || {};
    const isNew: boolean = !nodeData.id;
    let ret: any = undefined;
    if (isNew) {
      if (onCreateNode) {
        ret = await onCreateNode(nodeData);
      } else {
        flag = true;
      }
    } else {
      if (onUpdateNode) {
        ret = await onUpdateNode(nodeData);
      } else {
        flag = true;
      }
    }
    if (!flag && !!ret) {
      nodeData = ret;
      flag = true;
    }
    // 如果flag true 创建节点
    if (flag) {
      if (isNew) {
        addNewNode(nodeData);
      } else {
        updateNode(node);
      }
    }
    return flag;
  });

  return (
    <div ref={archWrapper} className="ra-arch-design">
      <Spin spinning={initLoading} tip="数据初始化中，请稍候...">
        <div className="ra-arch-aside">
          <List
            onNodeCreate={dragToCreateNode}
            configs={moduleConfig}
            graph={graph}
            assets={assetsData}
          />
        </div>
        <div className="ra-arch-content">
          <CreateNode
            visible={visible}
            onClose={() => setVisible(false)}
            node={currentCell as Node}
            laneOptions={laneOptions}
            onSubmit={submitNode}
          />
          <div className="ra-arch-actions">
            <ActionButtons
              onActions={handlerActions}
              isFullScreen={isFullScreen}
              canRedo={canRedo}
              canUndo={canUndo}
            />
          </div>
          <div className="ra-arch-laneGroup">
            <Lane
              setCurrentCell={setCurrentCell}
              data={graphData}
              onActions={handlerActions}
              onLoad={setGraph}
              assets={assetsData}
              zoom={zoom}
              isFullScreen={isFullScreen}
              setCanRedo={setCanRedo}
              setCanUndo={setCanUndo}
              onUndoOrRedo={onUndoOrRedo}
            />
          </div>
        </div>
      </Spin>
    </div>
  );
};

export default ArchDesign;
